package org.deri.feather.search;

import java.io.File;
import java.io.IOException;
import java.util.Vector;

import org.apache.lucene.analysis.KeywordAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.deri.feather.common.ConfigurationManager;
import org.deri.feather.common.Entity;
import org.deri.feather.common.IRIElement;
import org.deri.feather.common.LiteralElement;
import org.deri.feather.common.Triple;


public class Search {

	private IndexReader graphReader;	
	private IndexSearcher graphSearcher;
	
	private IndexReader valueReader;	
	private IndexSearcher valueSearcher;
	
	private int MAX_NUMBER_OF_RESULTS;
  
	public Search() {
		MAX_NUMBER_OF_RESULTS = 1000000;
	}
	
	public void setUp(){
		
		  try {

			MAX_NUMBER_OF_RESULTS = Integer.parseInt(ConfigurationManager.getInstance().getValue("max_number_of_results"));
			  
			System.out.print("Loading Indexes: ");

			String index = ConfigurationManager.getInstance().getValue("index");
			String GRAPH_INDEX_DIR = index + "/graph";
			String VALUE_INDEX_DIR = index + "/value";
			
			graphReader = IndexReader.open(FSDirectory.open(new File(GRAPH_INDEX_DIR)));
			graphSearcher = new IndexSearcher(graphReader);
			
			if (ConfigurationManager.getInstance().enableKeywordIndex() || ConfigurationManager.getInstance().enableLiteralIndex()) {
				valueReader = IndexReader.open(FSDirectory.open(new File(VALUE_INDEX_DIR)));
				valueSearcher = new IndexSearcher(valueReader);
			}
			
			System.out.print("[OK]\n");
			
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		
	public Vector<Triple> queryByTriplePattern(String subjectURI, String predicateURI, String objectURI){
		  
		Vector<Triple> triples = new Vector<Triple>();
		  
		try {

			BooleanQuery query = new BooleanQuery();
			if(!subjectURI.isEmpty()){
				TermQuery subQuery = new TermQuery(new Term("sub", subjectURI));
				query.add(subQuery, Occur.MUST);
			}

			if(!predicateURI.isEmpty()){
				TermQuery predQuery = new TermQuery(new Term("pred", predicateURI));
				query.add(predQuery, Occur.MUST);
			}
			
			if(!objectURI.isEmpty()){
				TermQuery objQuery = new TermQuery(new Term("obj", objectURI));
				query.add(objQuery, Occur.MUST);
			}
			
			TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_NUMBER_OF_RESULTS, true);
			graphSearcher.search(query, collector);
			ScoreDoc[] hits = collector.topDocs().scoreDocs;

			for(int i=0;i<hits.length;++i) {
				int docId = hits[i].doc;
				Document d = graphSearcher.doc(docId);
				Triple triple = new Triple(new IRIElement(d.get("sub")),new IRIElement(d.get("pred")), new LiteralElement(d.get("obj")));
				triples.add(triple);
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}

		return triples;
	}
	
	public Vector<Entity> valueSearch(String queryString, String namedGraphURI){
		if (!(ConfigurationManager.getInstance().enableKeywordIndex() || ConfigurationManager.getInstance().enableLiteralIndex())) {
			//FIXME Throw Exception
			System.out.println("This search is not available!!! ");
			return null;
		}
		
		Vector<Entity> entities = new Vector<Entity>();

		try {
			BooleanQuery query = new BooleanQuery();
			QueryParser queryParser = new QueryParser(Version.LUCENE_35, "value", new KeywordAnalyzer());
			query.add(queryParser.parse(QueryParser.escape(queryString)), Occur.SHOULD);
		
			TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_NUMBER_OF_RESULTS, true);
			valueSearcher.search(query, collector);
			ScoreDoc[] hits = collector.topDocs().scoreDocs;

			for(int i=0;i<hits.length;++i) {
				int docId = hits[i].doc;
				Document d = valueSearcher.doc(docId);
				//FIXME
				Entity entity = new Entity(d.get("uri"), d.get("value"));
				entities.add(entity);
			}
			
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return entities;
	}

}
